package com.hbzhit.common.shiro;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import com.hbzhit.common.shiro.dao.SessionDao;
import com.hbzhit.common.shiro.entity.SessionEntity;
import com.hbzhit.common.utils.SerializeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.ValidatingSession;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;

/**
 * shiro 会话操作类
 *
 * @author Tiger.Zhang
 * date 2019/11/11 15:31
 */
@Slf4j
public class ShiroSessionDAO extends EnterpriseCacheSessionDAO {

    @Autowired
    private SessionDao sessionDao;

    /**
     * 创建session
     * Create session 是第一次请求，如果浏览器没有jseesion就创建并写给浏览器
     * 如果安全管理器中的session失效了，用户登陆是携带jsessionid，先执行readSession，
     * 通过Jsessionid区找Session,找到了就给安全管理器，找不到就执行creatSession方法重新创建session。
     */
    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = super.doCreate(session);

        SessionEntity userSession = new SessionEntity();
        userSession.setId((String) session.getId());
        userSession.setContent(SerializeUtils.serialize(session));
        userSession.setCreateTime(DateTime.now());
        userSession.setUpdateTime(DateTime.now());
        sessionDao.insert(userSession);
        log.debug("Create session：" + session.getId());
        return sessionId;
    }

    /**
     * 读取session数据
     * @param sessionId 会话ID
     */
    @Override
    protected Session doReadSession(Serializable sessionId) {
        Session session = super.doReadSession(sessionId);

        if(session==null) {
            SessionEntity userSession = sessionDao.selectById(sessionId);
            if(userSession!=null) {
                session=(Session) SerializeUtils.deserialize(userSession.getContent());
                //如果库有，缓存却没有，加入缓存，readSession调用次数太多
                //super.doCreate(session);虽然可以加入缓存，但错误的 会产生新的seesionId
                cache(session, sessionId);
            }
        }
        log.debug("Read session：" + sessionId);
        return session;
    }

    /**
     * 更新session
     * shiro对每一次请求都会更新最后访问时间.当一个页面包含多个资源的时候就会发生多次update session
     */
    @Override
    protected void doUpdate(Session session) {
        if(session instanceof ValidatingSession && !((ValidatingSession)session).isValid()) {
            return; //如果会话过期/停止 没必要再更新了
        }

        SessionEntity userSession = new SessionEntity();
        userSession.setId(session.getId().toString());
        userSession.setContent(SerializeUtils.serialize(session));
        userSession.setUpdateTime(DateTime.now());
        Object uid = session.getAttribute("uid");
        log.debug("Update session: [uid]" + uid);
        if (ObjectUtil.isNotEmpty(uid)) {
            userSession.setUserId((Long) uid);
        }
        sessionDao.updateById(userSession);
        log.debug("Update session：" + session.getId());
    }

    /**
     * 删除session
     */
    @Override
    protected void doDelete(Session session) {
        sessionDao.deleteById(session.getId());
        log.debug("Delete session：" + session.getId());
    }
}
